package com.india.common.threads;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

public class ThreadPool {

    private Map<String, TimeUnit> _timeUnit;
    private Map<String, RejectedExecutionHandler> _handler;
    private static ThreadPool _instance;
    private ThreadPoolExecutor _threadPool;

    private ThreadPool() throws Exception {
        this(50, -1, 30,
                "SECONDS", -1, "DISCARDPOLICY");
    }

    private ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, String unitName, int workQueueNumber, String handerName) throws Exception {
        initTimeUnit();
        initHander();
        BlockingQueue<Runnable> workQueue = null;
        if (maximumPoolSize == -1) {
            if (workQueueNumber == -1) {
                workQueue = new SynchronousQueue<Runnable>();
            } else if (workQueueNumber == 0) {
                workQueue = new LinkedBlockingQueue<Runnable>();
            }
        } else {
            workQueue = new ArrayBlockingQueue<Runnable>(workQueueNumber);
            _threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, _timeUnit.get(unitName), workQueue, _handler.get(handerName));
        }

    }

    public static final ThreadPool getInstance() {
        if (_instance == null) {
            try {
                _instance = new ThreadPool();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return _instance;
    }

    public static final ThreadPool getInstanceByParams(int corePoolSize, int maximumPoolSize, long keepAliveTime, String unitName, int workQueueNumber, String handerName) {
        if (_instance == null) {
            try {
                _instance = new ThreadPool(corePoolSize, maximumPoolSize, keepAliveTime, unitName, workQueueNumber, handerName);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return _instance;
    }

    public String executeThread(Callable<String> task) {
        try {
            return _threadPool.submit(task).get();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public String[] executeThread(Callable<String>[] tasks) {
        String[] value = null;
        try {
            value = new String[tasks.length];
            for (int i = 0; i < value.length; i++) {
                value[i] = _threadPool.submit(tasks[i]).get();
            }
            return value;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public void executeThread(Runnable task) {
        _threadPool.execute(task);
    }

    public void executeThread(Runnable[] tasks) {
        for (Runnable task : tasks) {
            _threadPool.execute(task);
        }
    }

    public void finalize() throws Throwable {
        _threadPool.shutdown();
        _instance = null;
    }

    public void finalizeNow() throws Throwable {
        _threadPool.shutdownNow();
        _instance = null;
    }

    private void initTimeUnit() {
        _timeUnit = new HashMap<String, TimeUnit>();
        _timeUnit.put("NANOSECONDS", TimeUnit.NANOSECONDS);
        _timeUnit.put("MICROSECONDS", TimeUnit.MICROSECONDS);
        _timeUnit.put("MILLISECONDS", TimeUnit.MILLISECONDS);
        _timeUnit.put("SECONDS", TimeUnit.SECONDS);
    }

    private void initHander() {
        _handler = new HashMap<String, RejectedExecutionHandler>();
        _handler.put("ABORTPOLICY", new ThreadPoolExecutor.AbortPolicy());
        _handler.put("CALLERRUNSPOLICY", new ThreadPoolExecutor.CallerRunsPolicy());
        _handler.put("DISCARDOLDESTPOLICY", new ThreadPoolExecutor.DiscardOldestPolicy());
        _handler.put("DISCARDPOLICY", new ThreadPoolExecutor.DiscardPolicy());
    }

}
